package cn.ac.iie.kgmanager.controller;

import cn.ac.iie.kgmanager.domain.Node;
import cn.ac.iie.kgmanager.dto.Page;
import cn.ac.iie.kgmanager.dto.request.Request;
import cn.ac.iie.kgmanager.dto.response.Response;
import cn.ac.iie.kgmanager.exception.ParamException;
import cn.ac.iie.kgmanager.service.NodeService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.*;

/**
 * @ClassName NodeController
 * @Author tjh
 * @Date 19/6/12 上午10:04
 * @Version 1.0
 **/
@RestController
public class NodeController {
    @Autowired
    NodeService nodeService;
    /**
     * 功能描述: 批量插入节点
     * @Param: [request]
     * @Return: cn.ac.iie.kgmanager.dto.response.Response
     * @Author: syh
     * @Date: 2019/6/14 20:37
     */
    @PostMapping("/node/")
    public Response addNodes(@RequestBody Request<Node> request) {
        List<String> ids = new LinkedList<>();
        try {
            request.check();
            List<Node> nodes = new LinkedList<>();
            // 遍历获取每个节点
            for (Node node : request.getData()) {
                // 校验参数
                node.check();
                // 校验是否存在同名节点
                // 调用NodeService中根据名称查询方法
                Node nodeFromDB = nodeService.getNodeByName(node.getLabels(), node.getName());
                if(nodeFromDB != null) {
                    return Response.paramError(String.join(",", node.getLabels())+"中"+node.getName()+"已存在对应实体");
                }
                // 为节点构建ID
                String id = UUID.randomUUID().toString().replace("-", "").toLowerCase();
                node.setId(id);
                // 记录ID便于返回
                ids.add(id);
                // 记录要插入的节点
                nodes.add(node);
            }

            // 新增节点
            try {
                // 判断异常，如存在异常证明插入失败，则记录数据信息，便于返回
                nodeService.addNodes(nodes);
            } catch (Exception e) {
                // TODO 这里根据情况返回详细的错误信息
                return Response.databaseError("插入失败");
            }

            return Response.operateSucessAndHaveData(ids);
        } catch (ParamException pe) {
            return Response.paramError(pe.getMessage());
        }
    }

    /**
     * 功能描述: 批量删除节点
     * @Param: [ids]
     * @Return: cn.ac.iie.kgmanager.dto.response.Response
     * @Author: syh
     * @Date: 2019/6/14 20:37
     */
    @DeleteMapping("/node/{ids}")
    public Response deleteNodes(@PathVariable(value = "ids") String[] ids) {
        // 校验参数
        if(ids == null || ids.length <= 0) {
            return Response.paramError("id列表不能为空");
        }

        // 遍历id，查询数据库
        for (String id : ids) {
            Node nodeFromDB = nodeService.getNodeById(id);
            if(nodeFromDB == null) {
                // 为空证明未从数据库查询出结果，证明ID不合法
                return Response.paramError("id:"+id+"在数据库中未能找到对应数据，请检查");
            }
        }

        try {
            boolean flag = nodeService.deleteNodes(Arrays.asList(ids));

            return Response.operateSucessAndHaveData(ids.length);
        } catch (Exception e) {
            // TODO 这里根据情况返回详细的错误信息
            return Response.databaseError("节点删除失败");
        }
    }

    /**
     * 功能描述: 批量修改节点
     * @Param: [request]
     * @Return: cn.ac.iie.kgmanager.dto.response.Response
     * @Author: syh
     * @Date: 2019/6/14 20:38
     */
    @PutMapping("/node/")
    public Response updateNodes(@RequestBody Request<Node> request) {
        try{
            // 校验参数
            request.check();

            List<Node> nodes = request.getData();

            for (Node node : nodes) {
                String id = node.getId();
                String name = node.getName();
                Set<String> labels = node.getLabels();

                // 校验
                if(StringUtils.isBlank(id) || StringUtils.isBlank(name)) {
                    return Response.paramError("id和name不能为空");
                }

                // 查询id在库中是否有对应数据
                Node nodeById = nodeService.getNodeById(id);
                if(nodeById == null) {
                    // 为空证明未从数据库查询出结果，证明ID不合法
                    return Response.paramError("id:"+ id +"在数据库中未能找到对应数据，请检查");
                }

                // 查询修改后name是否有同名节点
                Node nodeByName = nodeService.getNodeByName(labels, name);
                if(nodeByName != null) {
                    // 证明修改后在库中有同名节点
                    return Response.paramError("label"+ labels +"name:"+name+"在数据库中已经存在");
                }
            }

            try {
                // 更新时注意比较数据库中已有数据和新增数据的label
                boolean flag = nodeService.updateNodes(nodes);
                return Response.operateSucessAndHaveData(nodes.size());
            } catch (Exception e) {
                // TODO 这里根据情况返回详细的错误信息
                return Response.databaseError("节点修改失败");
            }

        } catch (ParamException pe) {
            return Response.paramError(pe.getMessage());
        }
    }

    /**
     * 功能描述: 根据Id查询节点
     * @Param: [id]
     * @Return: cn.ac.iie.kgmanager.dto.response.Response
     * @Author: syh
     * @Date: 2019/6/14 20:38
     */
    @GetMapping("/node/{id}")
    public Response getNodeById(@PathVariable(value = "id") String id) {
        if(StringUtils.isBlank(id)) {
            return Response.paramError("id不能为空");
        }

        try {
            Node node = nodeService.getNodeById(id);
            return Response.operateSucessAndHaveData(node);
        } catch (Exception e) {
            // TODO 这里根据情况返回详细的错误信息
            return Response.databaseError("查询失败");
        }
    }

    /**
     * 功能描述: 根据名称和标签模糊查找，支持分页
     * @Param: [name, labels, pageNum, pageSize]
     * @Return: cn.ac.iie.kgmanager.dto.response.Response
     * @Author: syh
     * @Date: 2019/6/14 20:38
     */
    @GetMapping("/nodes/{name}")
    public Response getNodesByName(@PathVariable(value = "name", required = false) String name,
                                   @RequestParam(value = "labels", required = false) String[] labels,
                                   @RequestParam(value = "pageNum", required = false) Integer pageNum,
                                   @RequestParam(value = "pageSize", required = false) Integer pageSize) {
        Set<String> realLabels = new HashSet<>();
        realLabels.addAll(Arrays.asList(labels));
        // 判断label是否有重复
        if(realLabels.size() != labels.length) {
            return Response.paramError("传入节点类型有重复");
        }
        try {
            // 查询
            Page<Node> nodeLikeName = nodeService.getNodeLikeName(realLabels, name, pageNum, pageSize);
            return Response.operateSucessAndHaveDataAndPage(nodeLikeName, Long.parseLong(String.valueOf(nodeLikeName.getTotalSize())), nodeLikeName.getPageNum());
        } catch (Exception e) {
            // TODO 这里根据情况返回详细的错误信息
            return Response.databaseError("查询失败");
        }
    }

    /**
     * 功能描述: 根据Id，标签，层级深度查询周边关联节点，支持分页
     * @Param: [id, labels, depth, pageNum, pageSize]
     * @Return: cn.ac.iie.kgmanager.dto.response.Response
     * @Author: syh
     * @Date: 2019/6/14 20:39
     */
    @GetMapping("/node/{id}/nodes")
    public Response getAroundNodes(@PathVariable(value = "id") String id,
                                   @RequestParam(value = "labels", required = false) String[] labels,
                                   @RequestParam(value = "depth", required = false) Integer depth,
                                   @RequestParam(value = "pageNum", required = false) Integer pageNum,
                                   @RequestParam(value = "pageSize", required = false) Integer pageSize) {
        Set<String> realLabels = new HashSet<>();
        realLabels.addAll(Arrays.asList(labels));
        // 判断label是否有重复
        if(realLabels.size() != labels.length) {
            return Response.paramError("传入节点类型有重复");
        }

        // 查询id在库中是否有对应数据
        Node nodeById = nodeService.getNodeById(id);
        if(nodeById == null) {
            // 为空证明未从数据库查询出结果，证明ID不合法
            return Response.paramError("id:"+ id +"在数据库中未能找到对应数据，请检查");
        }

        try {
            Page<Node> aroundNodes = nodeService.getAroundNodes(id, realLabels, depth, pageNum, pageSize);
            return Response.operateSucessAndHaveDataAndPage(aroundNodes, Long.parseLong(String.valueOf(aroundNodes.getTotalSize())), aroundNodes.getPageNum());
        } catch (Exception e) {
            // TODO 这里根据情况返回详细的错误信息
            return Response.databaseError("查询失败");
        }
    }
}
